﻿/*
** Haaf's Game Engine 1.5
** Copyright (C) 2003-2004, Relish Games
** hge.relishgames.com
**
** hgeGUI helper classes header
*/
module core.hgegui;
 
private	import		core.hgeall;



const HGEGUI_NONAVKEYS		=0;
const HGEGUI_LEFTRIGHT		=1;
const HGEGUI_UPDOWN		=2;
const HGEGUI_CYCLED		=4;

class hgeGUI;

/*
** hgeGUIObject
*/
class hgeGUIObject
{
public:
	this()	{	if(!hge)hge = gameInfo.hge(); }

	 void	Render() {};
	 void	Update(float dt) {}

	 void	Enter() {}
	 void	Leave() {}
	 bool	IsDone() { return true; }
	 void	Focus(bool bFocused) {}
	 void	MouseOver(bool bOver) {}

	 bool	MouseMove(float x, float y) { return false; }
	 bool	MouseLButton(bool bDown) { return false; }
	 bool	MouseRButton(bool bDown) { return false; }
	 bool	MouseWheel(int nNotches) { return false; }
	 bool	KeyClick(int key, int chr) { return false; }

	int				id;
	bool			bStatic;
	bool			bVisible;
	bool			bEnabled;
	hgeRect			rect;

	hgeGUI			*gui;
	hgeGUIObject	*next;
	hgeGUIObject	*prev;

protected:
	hgeGUIObject( hgeGUIObject &go);
	hgeGUIObject&	operator= ( hgeGUIObject &go);

	static ifHge 	hge;
};


/*
** hgeGUI
*/
class hgeGUI
{
public:
	this()
	{
		if(!hge)hge = gameInfo.hge();

		ctrls=0;
		ctrlLock=0;
		ctrlFocus=0;
		ctrlOver=0;
		navmode=HGEGUI_NONAVKEYS;
		bLPressed=bLLastPressed=false;
		bRPressed=bRLastPressed=false;
		nWheel=0;
		mx=my=0.0f;
		nEnterLeave=0;
		sprCursor=0;
	}

	
	~this()
	{
		hgeGUIObject *ctrl=ctrls, *nextctrl;

		while(ctrl)
		{
			nextctrl=ctrl.next;
			delete ctrl;
			ctrl=nextctrl;
		}

	}
	

	void	AddCtrl(hgeGUIObject *ctrl)		// 加入控件
		{
			ctrl.gui=this;
			ctrls[ctrl.id]=ctrl;
		}


	void	DelCtrl(int id)
		{
			delete ctrls[id];
			ctrls.remove(id);
		}
	
	hgeGUIObject*	GetCtrl(int id)
				{
					return ctrls[id];
				}

	
	void MoveCtrl(int id, float x, float y)
			{
				hgeGUIObject ctrl=GetCtrl(id);
				ctrl.rect.x2= x + (ctrl.rect.x2 - ctrl.rect.x1);
				ctrl.rect.y2= y + (ctrl.rect.y2 - ctrl.rect.y1);
				ctrl.rect.x1= x;
				ctrl.rect.y1= y;
			}

	
	void	ShowCtrl(int id, bool bVisible)
		{
			GetCtrl(id).bVisible=bVisible;
		}

	
	void	EnableCtrl(int id, bool bEnabled)
		{
			GetCtrl(id).bEnabled=bEnabled;
		}

	void	SetNavMode(int mode)
			{
				navmode=mode;
			}
	void	SetCursor(hgeSprite *spr)
			{
				sprCursor=spr;
			}
	void	SetFocus(int id)
			{
				hgeGUIObject ctrlNewFocus=GetCtrl(id);

				if(ctrlNewFocus is ctrlFocus) return;
				if(!ctrlNewFocus)
				{
					if(ctrlFocus) ctrlFocus.Focus(false);
					ctrlFocus=0;
				}
				else if(!ctrlNewFocus.bStatic && ctrlNewFocus.bVisible && ctrlNewFocus.bEnabled)
				{
					if(ctrlFocus) ctrlFocus.Focus(false);
					if(ctrlNewFocus) ctrlNewFocus.Focus(true);
					ctrlFocus=ctrlNewFocus;
				}
			}
	int	 GetFocus() const
		{
			if(ctrlFocus) return ctrlFocus.id;
			else return 0;
		}
	
	void Enter()
			{
				foreach(inout ctrl; ctrls)
				{
					ctrl.Enter();
				}
				nEnterLeave=2;
			}
	void Leave()
			{
				foreach(inout ctrl; ctrls)
				{
					ctrl.Leave();
				}
				ctrlFocus=0;
				ctrlOver=0;
				ctrlLock=0;
				nEnterLeave=1;
			}

	int		Update(float dt)
			{
				bool bDone;
				int key;
			// Update the mouse variables

				hge.Input_GetMousePos(&mx, &my);
				bLLastPressed=bLPressed;
				bLPressed=hge.Input_GetKeyState(VK_LBUTTON);
				bRLastPressed=bRPressed;
				bRPressed=hge.Input_GetKeyState(VK_RBUTTON);
				nWheel=hge.Input_GetMouseWheel();

			// Update all controls
				foreach(inout ctrl; ctrls)
				{
					ctrl.Update(dt);
				}

			// Handle Enter/Leave

				if(nEnterLeave)
				{
					bDone=true;
					foreach(inout ctrl; ctrls)
					{
						if(!ctrl.IsDone()) { bDone=false; break; }
					}
					if(!bDone) return 0;
					else
					{
						if(nEnterLeave==1) return -1;
						else nEnterLeave=0;
					}
				}

			// Handle keys	
				//hgeGUIObject ctrl;		/////////////////////////////		 yish 		//////////////////
				hgeGUIObject ct;
				key=hge.Input_GetKey();
				if(((navmode & HGEGUI_LEFTRIGHT) && key==HGEK_LEFT) ||
					((navmode & HGEGUI_UPDOWN) && key==HGEK_UP))
				{
					//ctrl=ctrlFocus;		//取到当前焦点控件
					if(!ctrlFocus)			// 如果当前没有
					{
						//ctrl=ctrls;	// 就从全部控件中开始
						if(ctrls.length==0) return 0;	//测试 ctrls 数组的数量不为0
					}
					
				/*	do {				// 从指定的控件开始顺序移动焦点
						ctrl=ctrl.prev;		// 取前一个控件
						if(!ctrl && ((navmode & HGEGUI_CYCLED) || !ctrlFocus))	// 如果 该控件为空 或 无焦点
						{
							ctrl=ctrls;				// 再从全部控件中开始选取
							while(ctrl.next) ctrl=ctrl.next;		//找到 没有NEXT 的那个控件
						}
						if(!ctrl || ctrl==ctrlFocus) break;		//如果 控件为空 或 控件就是原来拥有焦点的那个,则跳出
					} while(ctrl.bStatic==true || ctrl.bVisible==false || ctrl.bEnabled==false);  // 只要符合 静态,不可视,非激活 状态的控件 就一直循环
				*/
					
					bool begin= false;
					bool bOK	= false;
					foreach(inout ctrl; ctrls){
						if(!ctrl && ((navmode & HGEGUI_CYCLED) || !ctrlFocus))
						if(ctrl.id == ctrlFocus.id)	{
							begin=true;
							continue;		// 跳过 当前焦点控件
						}

						if(begin)			// 已经遍历到当前焦点之后
						{
							if(! (ctrl.bStatic==true || ctrl.bVisible==false || ctrl.bEnabled==false))
							{
								ct=ctrl;
								break;
							}
						}else if(!bOK && !(ctrl.bStatic==true || ctrl.bVisible==false || ctrl.bEnabled==false))
						{		// 焦点之前的控件如果符合条件,先保存起来
							ct=ctrl;
							bok= true;	//保存后就不再进入此判断
						}
								
						
					}

					if(ct && ct!=ctrlFocus)
					{
						if(ctrlFocus) ctrlFocus.Focus(false);
						if(ct) ct.Focus(true);		//取消当前焦点, 激活 此控件焦点
						ctrlFocus=ct;
					}
				}
				else if(((navmode & HGEGUI_LEFTRIGHT) && key==HGEK_RIGHT) ||
					((navmode & HGEGUI_UPDOWN) && key==HGEK_DOWN))
				{
					ct=ctrlFocus;
					if(!ct)
					{
						if(ctrls.length==0) return 0;
						
					}
					do {
						ctrl=ctrl.next;
						if(!ctrl && ((navmode & HGEGUI_CYCLED) || !ctrlFocus)) ctrl=ctrls;
						if(!ctrl || ctrl==ctrlFocus) break;
					} while(ctrl.bStatic==true || ctrl.bVisible==false || ctrl.bEnabled==false);

					begin= false;
					bOK	= false;
					foreach(inout ctrl; ctrls){
						
						if(ctrl.id == ctrlFocus.id)	{
							begin=true;
							continue;		// 跳过 当前焦点控件
						}

						if(begin)			// 已经遍历到当前焦点之后
						{
							if(! (ctrl.bStatic==true || ctrl.bVisible==false || ctrl.bEnabled==false))
							{
								ct=ctrl;
								break;
							}
						}else if(!bOK && !(ctrl.bStatic==true || ctrl.bVisible==false || ctrl.bEnabled==false))
						{		// 焦点之前的控件如果符合条件,先保存起来
							ct=ctrl;
							bok= true;	//保存后就不再进入此判断
						}
					}













					if(ctrl && ctrl!=ctrlFocus)
					{
						if(ctrlFocus) ctrlFocus.Focus(false);
						if(ctrl) ctrl.Focus(true);
						ctrlFocus=ctrl;
					}
				}
				else if(ctrlFocus && key && key!=HGEK_LBUTTON && key!=HGEK_RBUTTON)
				{
					if(ctrlFocus.KeyClick(key, hge.Input_GetChar())) return ctrlFocus.id;
				}

			// Handle mouse

				if(ctrlLock)
				{
					ctrl=ctrlLock;
					if(!bLPressed && !bRPressed) ctrlLock=0;
					if(ProcessCtrl(ctrl)) return ctrl.id;
				}
				else
				{
					// Find last (topmost) control

					ctrl=ctrls;
					if(ctrl)
						while(ctrl.next) ctrl=ctrl.next;

					while(ctrl)
					{
						if(ctrl.rect.TestPoint(mx,my) && ctrl.bEnabled)
						{
							if(ctrlOver != ctrl)
							{
								if(ctrlOver) ctrlOver.MouseOver(false);
								ctrl.MouseOver(true);
								ctrlOver=ctrl;
							}

							if(ProcessCtrl(ctrl)) return ctrl.id;
							else return 0;
						}
						ctrl=ctrl.prev;
					}

					if(ctrlOver) {ctrlOver.MouseOver(false); ctrlOver=0;}

				}

				return 0;
			}
	
	void	Render()
			{
				hgeGUIObject *ctrl=ctrls;

				while(ctrl)
				{
					if(ctrl.bVisible) ctrl.Render();
					ctrl=ctrl.next;
				}

				if(hge.Input_IsMouseOver() && sprCursor) sprCursor.Render(mx,my);
			}

private:
	this( hgeGUI gu){
		
		this.ctrls=		gu.ctrls;
		this.ctrlLock=	gu.ctrlLock;
		this.ctrlFocus=	gu.ctrlFocus;
		this.ctrlOver=	gu.ctrlOver;
		this.navmode=	gu.navmode;
		this.bLPressed= gu.bLPressed;
		this.bLLastPressed= gu.bLLastPressed;
		this.bRPressed=	gu.bRPressed;
		this.bRLastPressed=	gu.bRLastPressed;
		this.nWheel=gu.nWheel;
		this.mx=gu.mx;
		this.my=gu.my;
		this.nEnterLeave=gu.nEnterLeave;
		this.sprCursor=gu.sprCursor;
		};
		
	//hgeGUI&			operator= (const hgeGUI&);
	hgeGUI	opCatAssign(hgeGUI gu){	this(gu);	return gu;}		//  用~= 连赋值 代替  = 操作符 
	
	bool	ProcessCtrl(hgeGUIObject *ctrl)
			{
				bool bResult=false;

				if(!bLLastPressed && bLPressed)	{ ctrlLock=ctrl;SetFocus(ctrl.id);bResult=bResult || ctrl.MouseLButton(true); }
				if(!bRLastPressed && bRPressed)	{ ctrlLock=ctrl;SetFocus(ctrl.id);bResult=bResult || ctrl.MouseRButton(true); }
				if(bLLastPressed && !bLPressed)	{ bResult=bResult || ctrl.MouseLButton(false); }
				if(bRLastPressed && !bRPressed)	{ bResult=bResult || ctrl.MouseRButton(false); }
				if(nWheel) bResult=bResult || ctrl.MouseWheel(nWheel);
				bResult=bResult || ctrl.MouseMove(mx-ctrl.rect.x1,my-ctrl.rect.y1);

				return bResult;
			}

	static ifHge 	hge;

	hgeGUIObject[int]	ctrls;
	hgeGUIObject	*ctrlLock;
	hgeGUIObject	*ctrlFocus;
	hgeGUIObject	*ctrlOver;

	int				navmode;
	int				nEnterLeave;
	hgeSprite		*sprCursor;

	float			mx,my;
	int				nWheel;
	bool			bLPressed, bLLastPressed;
	bool			bRPressed, bRLastPressed;
};

